package com.itheima.tliasmanager.interceptor;

import com.itheima.tliasmanager.utils.ApplicationContext;
import com.itheima.tliasmanager.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

/**
 * 统一登录校验  拦截器
 *      校验用户是否登录过，用户是否验证过身份
 */
@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {


    /**
     * 拦截所有请求的处理方法
     *      校验用户是否登录过，用户是否验证过身份
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("拦截器，当前线程名称：{}",Thread.currentThread().getName());


        //3.获取令牌Token（请求头中：token=令牌）
        String token = request.getHeader("token");

        //4.判断令牌是否为空
        if( token == null ){
            log.info("LoginInterceptor拦截请求：没有令牌，直接封装未授权响应结果");
            //如果令牌为空，直接封装处理结果（设置响应码401：未授权，前端统一处理401响应状态码，直接跳转登录页面）
            response.setStatus(401);
            return false; //注意：登录后，回到过滤器执行过滤后的操作；直接返回，跳过过滤后的操作
        }

        //5.如果携带了令牌，则解析令牌
        try {
            Claims claims = JwtUtils.parseJWT(token);//刷门禁卡

            Integer  id = (Integer) claims.get("id");
            //将当前操作人员的id存储到当前线程的ThreadLocalMap集合中
            ApplicationContext.setEmpId(id);


        } catch (Exception e) {
            log.info("LoginInterceptor拦截请求：令牌无效，直接封装未授权响应结果");
            //如果解析令牌失败，则直接封装处理结果（设置响应码401：未授权，前端统一处理401响应状态码，直接跳转登录页面）
            response.setStatus(401);
            return false; //注意：登录后，回到过滤器执行过滤后的操作；直接返回，跳过过滤后的操作
        }

        //6.如果解析令牌成功，放行
        log.info("LoginInterceptor拦截请求：令牌有效，直接放行");
        return true;
    }


    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        //3.清空ThreadLocal中数据：防止内存泄露（ThreadLocal操作的线程的map集合中的key是弱引用，可能会被GC回收，value永远存在无法操作）
        ApplicationContext.clear();
    }
}
